#ifndef __MVT_SOCKET_H__
#define __MVT_SOCKET_H__

#include "mvdef.h"

MVCXX_EXTERN_BEGIN

/**
 * @brief 已支持IPV6操作
 * @note  socket使用推荐
 * - server = (socket + bind + listen)  优先 ipv6，可兼容ipv4/6的连接请求
 * - client = (socket + bind + connect) 优先 ipv4，可被ipv4/6的server兼容接受
 * @note  udp socket
 * - (bind 可被对端sendto或connect, connect 可使用send和recv)
 * - bind + connect (send   + recv     双端指定端口)
 * - connect        (send   + recv     对端指定端口，本端随机端口)
 * - bind           (sendto + recvfrom 指定本端端口)
 * - nothing        (sendto only       这里统一操作，必须调用bind，端口可以为0特殊标识)
 */

typedef enum _mvt_socket_type {
    MVT_TCP_SOCKET = 0,
    MVT_TLS_SOCKET = 1,
    MVT_UDP_SOCKET = 2,
} mvt_socket_type_e;

typedef enum _mvt_protocol_family {
    MVT_SOCKET_PF_UNSPEC = 0,
    MVT_SOCKET_PF_IPV4   = 1,
    MVT_SOCKET_PF_IPV6   = 2,
} mvt_socket_pf_e;

typedef struct _mvt_sockaddr
{
    mv_u8_t u8_is_ipv6;             ///< 0=ipv4, 1=ipv6
    union {                         ///< 等价联合体，分别等价 sin6_addr/sin_addr.s_addr
        mv_u32_t u32_nipv4;         ///< 使用IPv4类型时，填充/使用此参数；pton(AF_INET,  ..., &u32_nipv4)
        union {
            mv_u16_t au16_nipv6[8]; ///< (方便按段使用数据)
            mv_v8_t  av8_nipv6[16]; ///< 使用IPv6类型时，填充/使用此参数；pton(AF_INET6, ..., av8_nipv6) 
        };
        mv_u8_t  au8_addr[32];      ///< (方便按字节使用等价成员)
    };
    mv_u16_t u16_nport;             ///< port in netseq format
}mvt_sockaddr_t;
/**
 * @brief 等价封装inet_ntop
 * 
 * @param e_pf     [in] 指定转换协议类型
 * @param cpsrc    [in] 源数据地址(IP数值)
 * @param pv8_dst  [in] 转换结果缓存地址
 * @param s32_size [in] 缓存大小
 * @return 转换结果
 * - success : 指向pv8_buffer首地址
 * -  failed : NULL
 */
mv_cv8ptr_t mvt_socket_ntop(mvt_socket_pf_e e_pf, mv_cvptr_t cpsrc, mv_v8ptr_t pv8_dst, mv_s32_t s32_size);
/**
 * @brief 等价封装inet_pton
 * 
 * @param e_pf       [in] 指定转换协议类型
 * @param cp         [in] 源数据地址(字符串)
 * @param p_buffer   [in] 转换结果缓存地址
 * @return 转换结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 * 
 * @attention p_buffer内存长度，IPV4必须为4字节，IPV6至少16字节缓冲，否则会出现内存问题！
 */
mv_s32_t    mvt_socket_pton(mvt_socket_pf_e e_pf, mv_cv8ptr_t cp, mv_vptr_t  p_buffer);

/**
 * @brief 等价封装hton和ntoh系列
 */
#if __BYTE_ORDER__ ==__ORDER_BIG_ENDIAN__
#define mvt_socket_htonl(u32_val) u32_val
#define mvt_socket_htons(u16_val) u16_val
#else
#define mvt_socket_htonl(u32_val) ((((u32_val)&0xff000000)>>24)|(((u32_val)&0x00ff0000)>>8)|(((u32_val)&0x000000ff)<<24)|(((u32_val)&0x0000ff00)<<8))
#define mvt_socket_htons(u16_val) ((((u16_val)&0xff00)>>8)|(((u16_val)&0x00ff)<<8))
#endif
#define mvt_socket_ntohl(u32_val) mvt_socket_htonl(u32_val)
#define mvt_socket_ntohs(u16_val) mvt_socket_htons(u16_val)

typedef struct _host_ip
{
    mv_u8_t u8_is_ipv6;         ///< 0=ipv4, 1=ipv6
    union {                     ///< 等价联合体，分别等价 sin6_addr/sin_addr.s_addr
        mv_v8_t  av8_nipv6[16]; ///< 使用IPv6类型时，填充/使用此参数；pton(AF_INET6, ..., av8_nipv6) 
        mv_u32_t u32_nipv4;     ///< 使用IPv4类型时，填充/使用此参数；pton(AF_INET,  ..., &u32_nipv4)
    };
}mvt_socket_hostip_t;
/**
 * @brief 进阶封装getaddrinfo等效
 * 
 * @param cpv8_hostname [in] IP地址或域名(字符串)
 * @param e_spec_pf     [in] 指定解析类型(*UNSPEC则全类型解析)
 * @param astru_sa      [in] 解析结果缓存区
 * @param s32_num       [in] 缓存区数量
 * @param s32_timeout_ms[in] 解析超时时间（ms；仅SDNS接管接接口有效）
 * @return 解析结果数量
 * - success : >= 0
 * -  failed : else
 */
mv_s32_t   mvt_socket_get_ip_from_hostname_r(mv_cv8ptr_t cpv8_hostname, mvt_socket_pf_e e_spec_pf, mvt_sockaddr_t astru_sa[], mv_s32_t s32_num, mv_s32_t s32_timeout_ms);
mv_s32_t   mvt_socket_get_ip_from_hostname  (mv_cv8ptr_t cpv8_hostname, mvt_socket_pf_e e_spec_pf, mvt_sockaddr_t astru_sa[], mv_s32_t s32_num); ///< 默认超时
/**
 * @brief mvt_socket句柄创建
 * 
 * @param e_socket_type [in] 即将创建的socket类型
 * @param pu8_run_flag  [in] 运行状态控制标识（*可选，NULL=不使用；标识值定义非1为自动中断，带超时的接口均以MV_EC_ABORT状态返回）
 * @param p_log         [in] mvt_log联动句柄（*可选，NULL=不启用）
 * @return 创建结果 \n
 * - success : mvt_socket句柄
 * -  failed : NULL
 * @note 下面所有mvt_socket操作集，均需要使用成功创建的mvt_socket句柄 \n 
 *       如果是TLS类型socket需要指定证书目录，请使用指定接口"mvt_tls_socket_create"进行创建 \n
 *       如果是TLS类型socket需要指定证书链(内存缓存型)，请使用指定接口"mvt_tls_socket_create_mem"进行创建 \n
 *       如果是UDP类型socket，必须bind或connect后，再进行正常使用
 */
mv_vptr_t mvt_socket_create(mvt_socket_type_e e_socket_type, mv_u8ptr_t pu8_run_flag, mv_vptr_t p_log);
/**
 * @brief mvt_socket句柄创建(针对TLS支持证书目录设置)
 * 
 * @param av8_pem_dir   [in] 证书链存放目录（NULL则等价于"mvt_socket_create"）
 * @param pu8_run_flag  [in] 运行状态控制标识（*可选，NULL=不使用；标识值定义非1为自动中断，带超时的接口均以MV_EC_ABORT状态返回）
 * @param p_log         [in] mvt_log联动句柄（*可选，NULL=不启用）
 * @return 创建结果 \n
 * - success : mvt_socket句柄
 * -  failed : NULL
 * @note 如果不需要指定证书目录，也可以使用通用接口"mvt_socket_create"创建
 */
mv_vptr_t mvt_tls_socket_create(mv_v8_t av8_pem_dir[256], mv_u8ptr_t pu8_run_flag, mv_vptr_t p_log);
/**
 * @brief mvt_socket句柄创建(针对TLS支持证书链内容设置)
 * 
 * @param cpv8_pem_dat_chain [in] 证书链缓存地址（NULL则等价于"mvt_socket_create"）
 * @param s32_len            [in] 证书链缓存内容长度
 * @param pu8_run_flag  [in] 运行状态控制标识（*可选，NULL=不使用；标识值定义非1为自动中断，带超时的接口均以MV_EC_ABORT状态返回）
 * @param p_log         [in] mvt_log联动句柄（*可选，NULL=不启用）
 * @return 创建结果 \n
 * - success : mvt_socket句柄
 * -  failed : NULL
 * 
 * @attention 注意证书链缓存使用动态内存时，不要提前释放（在destroy后再释放，避免重复connect时出现内存问题）
 * @attention 证书链的末尾，必须时'\0'结束（长度要包含'\0'）
 */
mv_vptr_t mvt_tls_socket_create_mem(mv_cv8ptr_t cpv8_pem_dat_chain, mv_s32_t s32_len, mv_u8ptr_t pu8_run_flag, mv_vptr_t p_log);
/**
 * @brief mvt_socket句柄销毁
 * 
 * @param p_handle [in] 需要销毁的mvt_socket句柄地址
 * @return /
 * @note 当mvt_socket不再使用时，记得要调用destroy释放占用的内存资源
 */
mv_void_t mvt_socket_destroy(mv_vptr_t *p_handle);
/**
 * @brief mvt_socket句柄设置log句柄关联操作
 * 
 * @param p_handle  [in] 有效的mvt_socket句柄
 * @param phdl_log  [in] mvt log句柄
 * @param u8_region [in] log句柄控制区域
 * @return mv_void_t 
 *
 * @note mvt_log.h模块的log控制句柄，作为工具模块，允许设置作为外部主句柄的其中一个区域使用
 *       此接口设置后，后续接口动态入参的log句柄参数将忽略（接口不变只是为了兼容）
 */
mv_void_t mvt_socket_log_set(mv_vptr_t p_handle, mv_vptr_t phdl_log, mv_u8_t u8_region);
/**
 * @brief mvt_socket句柄转sockfd
 * 
 * @param p_handle [in] 有效的mvt_socket句柄
 * @return sockfd
 * - success : sockfd
 * -  failed : < 0
 * @note 提供用于提取sockfd，自行实现比较复杂的getsockopt/setsockopt操作
 */
mv_s32_t  mvt_socket_fd(mv_vptr_t p_handle);
/**
 * @brief mvt_socket句柄当前绑定的sockaddr信息
 * 
 * @param p_handle [in] 有效的mvt_socket句柄
 * @param pstru_sa [in] sockaddr信息缓冲区
 * @return 操作结果
 * - success : MV_EC_SUCCESS
 * -  failed : else 
 */
mv_s32_t  mvt_socket_sa(mv_vptr_t p_handle, mvt_sockaddr_t *pstru_sa);
/**
 * @brief 设置TCP/TLS类型socket的MSS（慎用）
 * 
 * @param p_handle [in] 未"connect"的mvt_socket句柄
 * @param s32_mss  [in] 期望MSS值
 * @return 操作结果
 * - success : MV_EC_SUCCESS
 * -  failed : else
 */
mv_s32_t  mvt_socket_set_mss(mv_vptr_t p_handle, mv_s32_t s32_mss);

typedef enum _mvt_socket_option
{
    MVT_SO_INVALID = 0,
    MVT_SO_NONBLOCK,     ///< parg = (mv_s32ptr_t); 非阻塞  （0=阻塞；      1=非阻塞-默认）
    MVT_SO_BROADCAST,    ///< parg = (mv_s32ptr_t); 广播接收（0=不接收-默认；1=接收广播报文）
}mvt_socket_opt_e;
/**
 * @brief 设置socket的一些支持的常用属性
 * 
 * @param p_handle [in] 有效的mvt_socket句柄
 * @param parg     [in] 属性操作参数（务必根据属性枚举的注释描述进行传参，否则引起未知异常！）
 * @return 操作结果
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_NOT_SUPPORT (当前socket不支持此属性) 
 *             else
 */
mv_s32_t  mvt_socket_set_opt(mv_vptr_t p_handle, mvt_socket_opt_e e_opt, mv_vptr_t parg);
/**
 * @brief 连接到目标
 * 
 * @param p_handle        [in] 未"connect"的mvt_socket句柄
 * @param cpv8_addr       [in] 目标IP地址/域名（字符串形式）
 * @param u16_port        [in] 目标端口
 * @param s32_timeout_ms  [in] 连接操作超时限制（ms）
 * @param s32_try_times   [in] 尝试次数
 * @return 连接结果 \n
 * - success : MV_EC_SUCCESS
 * -  failed : else
 * @note UDP类型调用此接口成功后 \n
 * - 启用mvt_socket_send和mvt_socket_recv; \n
 * - 禁用mvt_socket_sendto和mvt_socket_recvfrom
 */
mv_s32_t  mvt_socket_connect (mv_vptr_t p_handle, mv_cv8ptr_t cpv8_addr, mv_u16_t u16_port, mv_s32_t s32_timeout_ms, mv_s32_t s32_try_times);
/**
 * @brief 设置断开连接时socket动作
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @param u8_swc          [in] 关闭时立即截断(Shutdown When Close): 0=disable; 1=RD; 2=WR; 3=RDWR
 * @param u8_lwc          [in] 关闭时待发保持(Linger When Close)  : 0=disable; else Linger Seconds
 * @return \
 * 
 * @note swc优先于lwc生效 ; 默认不设置就是全0，普通close
 */
mv_void_t  mvt_socket_act_when_disconnect(mv_vptr_t p_handle, mv_u8_t u8_swc, mv_u8_t u8_lwc);
/**
 * @brief 断开连接
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @return /
 */
mv_void_t mvt_socket_disconnect(mv_vptr_t p_handle);
/**
 * @brief 绑定本地IP、Port
 * 
 * @param p_handle        [in] 有效的mvt_socket句柄
 * @param pstru_addr      [in] 指定绑定网络信息（协议类型、IP、端口）
 * @return 操作结果 \n 
 * - success : MV_EC_SUCCESS
 * -  failed : MV_SOCKET_ERR
 * @note 此接口对于不同类型socket，有不同意义 \n 
 * - TLS : 不支持（无效）
 * - TCP : 绑定操作(作为client，推荐IPv4；作为server，推荐IPv6)
 * - UDP : 绑定操作(作为主动方，推荐IPv4；作为被动方，推荐IPv6)
 */
mv_s32_t  mvt_socket_bind(mv_vptr_t p_handle, mvt_sockaddr_t *pstru_addr);
/**
 * @brief socket进入listen模式
 * 
 * @param p_handle        [in] 未"connect"的mvt_socket句柄
 * @param s32_max_cnt     [in] 等待队列最大数量
 * @return 操作结果 \n 
 * - success : MV_EC_SUCCESS
 * -  failed : MV_SOCKET_ERR / MV_EC_NOT_SUPPORT
 * @note 此接口仅TCP类型socket有效 \n 
 * - TLS : 不支持（无效）
 * - TCP : 变成listen用socket
 * - UDP : 不支持（无效）
 */
mv_s32_t  mvt_socket_listen(mv_vptr_t p_handle, mv_s32_t s32_max_cnt);
/**
 * @brief 接受一个新的连接请求
 * 
 * @param p_handle        [in] 已"listen"的mvt_socket句柄
 * @param p_new_handle    [in] 用于承载新连接信息的干净的mvt_socket句柄
 * @param s32_timeout_ms  [in] 接受查询超时时限（ms）
 * @return 操作结果
 * - success : MV_EC_SUCCESS
 * -  failed : MV_EC_TIMEOUT / MV_EC_SOCKET_ERR / MV_EC_NOT_SUPPORT
 * @note 此接口仅TCP类型socket有效
 */
mv_s32_t  mvt_socket_accept(mv_vptr_t p_handle, mv_vptr_t p_new_handle, mv_s32_t s32_timeout_ms);
/**
 * @brief 接受一个新的连接请求EX
 * 
 * @param p_handle        [in] 已"listen"的mvt_socket句柄
 * @param s32_timeout_ms  [in] 接受查询超时时限（ms）
 * @param ps32_result    [out] 返回值取出MV_EC_SUCCESS / MV_EC_TIMEOUT / MV_EC_SOCKET_ERR / MV_EC_NOT_SUPPORT
 * @return 操作结果
 * - success : 接受的Client socket句柄
 * -  failed : NULL
 * @note 此接口仅TCP类型socket有效
 */
mv_vptr_t mvt_socket_accept_ex(mv_vptr_t p_handle, mv_s32_t s32_timeout_ms, mv_s32ptr_t ps32_result);
/**
 * @brief 数据发送
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @param cp_data         [in] 待发送数据
 * @param ssz_len         [in] 数据长度
 * @param s32_timeout_ms  [in] 发送超时时限（ms）
 * @return 发送结果
 * - success : 实际发送数据量
 * -  failed : < 0 (MV_EC_SOCKET_ERROR / MV_EC_TIMEOUT / MV_EC_INVALID_ARGS)
 */
mv_ssize_t  mvt_socket_send(mv_vptr_t p_handle, mv_cvptr_t cp_data, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms);
/**
 * @brief 数据接收（模糊数据量）
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @param p_data          [in] 数据接收缓冲区
 * @param ssz_len         [in] 最大接收长度
 * @param s32_timeout_ms  [in] 接收超时时限（ms）
 * @return 发送结果
 * - success : 实际接收数据量
 * -  failed : < 0 (MV_EC_SOCKET_ERROR / MV_EC_TIMEOUT / MV_EC_INVALID_ARGS)
 */
mv_ssize_t  mvt_socket_recv(mv_vptr_t p_handle, mv_vptr_t p_data, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms);
/**
 * @brief 数据接收（确切数据量）
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @param p_data          [in] 数据接收缓冲区
 * @param ssz_ext_len     [in] 目标接收长度
 * @param s32_timeout_ms  [in] 接收超时时限（ms）
 * @return 发送结果
 * - success : 实际接收数据量
 * -  failed : < 0 (MV_EC_SOCKET_ERROR / MV_EC_TIMEOUT / MV_EC_INVALID_ARGS)
 */
mv_ssize_t  mvt_socket_recv_ext(mv_vptr_t p_handle, mv_vptr_t p_data, mv_ssize_t ssz_ext_len, mv_s32_t s32_timeout_ms);
/**
 * @brief 数据发送(UDP only)
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @param cp_data         [in] 待发送数据
 * @param ssz_len         [in] 数据长度
 * @param s32_timeout_ms  [in] 发送超时时限（ms）
 * @param pstru_addr      [in] 目标网络信息（协议类型、IP、端口）
 * @return 发送结果
 * - success : 实际发送数据量
 * -  failed : < 0 (MV_EC_SOCKET_ERROR / MV_EC_TIMEOUT / MV_EC_INVALID_ARGS)
 * @note 非UDP类型socket，自动等效替换成mvt_socket_send调用
 */
mv_ssize_t  mvt_socket_sendto(mv_vptr_t p_handle, mv_cvptr_t cp_data, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms, mvt_sockaddr_t *pstru_addr);
/**
 * @brief 数据接收(UDP only)
 * 
 * @param p_handle        [in] 已"connect"的mvt_socket句柄
 * @param p_data          [in] 数据接收缓冲区
 * @param ssz_len         [in] 目标/最大接收长度
 * @param s32_timeout_ms  [in] 接收超时时限（ms）
 * @param pstru_addr     [out] 来源网络信息（协议类型、IP、端口）
 * @return 发送结果
 * - success : 实际接收数据量
 * -  failed : < 0 (MV_EC_SOCKET_ERROR / MV_EC_TIMEOUT / MV_EC_INVALID_ARGS)
 * @note 非UDP类型socket，自动等效替换成mvt_socket_send调用
 */
mv_ssize_t  mvt_socket_recvfrom(mv_vptr_t p_handle, mv_vptr_t p_data, mv_ssize_t ssz_len, mv_s32_t s32_timeout_ms, mvt_sockaddr_t *pstru_addr);

MVCXX_EXTERN_END

#endif